package com.sikaryofficial.system.manager.report;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSONObject;
import com.sikaryofficial.common.core.constant.CacheConstants;
import com.sikaryofficial.common.core.constant.ReportConstant;
import com.sikaryofficial.common.core.utils.DateUtils;
import com.sikaryofficial.common.redis.service.RedisService;
import com.sikaryofficial.system.api.model.ManualExportReq;
import com.sikaryofficial.system.api.model.user.UserDailyDTO;
import com.sikaryofficial.system.api.model.user.UserRegisterDTO;
import com.sikaryofficial.system.domain.PointsBalance;
import com.sikaryofficial.system.domain.SysUserDaily;
import com.sikaryofficial.system.domain.dto.SysMemberUserListDTO;
import com.sikaryofficial.system.domain.dto.TrendDTO;
import com.sikaryofficial.system.domain.dto.TrendReq;
import com.sikaryofficial.system.service.IPointBalanceService;
import com.sikaryofficial.system.service.ISysRegisterDailyService;
import com.sikaryofficial.system.service.ISysUserDailyService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author : qinjinyuan
 * @desc :
 * @date : 2024/03/02 21:08
 */
@Service
@Slf4j
public class ReportManager {
    @Autowired
    private RedisService redisService;
    @Autowired
    private ISysRegisterDailyService registerDailyService;
    @Autowired
    private ISysUserDailyService sysUserDailyService;
    @Autowired
    private IPointBalanceService pointBalanceService;

    /**
     * 留存率
     *
     * @param req
     * @return
     */
    public List<TrendDTO> retentionTrend(TrendReq req) {
        // 数据 查询
        Long total = sysUserDailyService.countDailyByDate(req);
        if (Objects.isNull(total)) {
            return Lists.newArrayList();
        }
        List<TrendDTO> trendResult = sysUserDailyService.getDailyByDate(req);
        int size = trendResult.size();
        for (int i = 0; i < size; i++) {
            if (i + 1 > size - 1) {
                trendResult.get(i).setDayRetentionRate(BigDecimal.TEN.multiply(BigDecimal.TEN));
                continue;
            }
            Long beforeTotal = trendResult.get(i + 1).getSubTotal();
            trendResult.get(i).setBeforeSubTotal(beforeTotal);
            Long curTotal = trendResult.get(i).getSubTotal();
            if (curTotal == 0) {
                trendResult.get(i).setDayRetentionRate(BigDecimal.ZERO);
                continue;
            }
            BigDecimal dayRetentionRate = BigDecimal.valueOf(beforeTotal).multiply(BigDecimal.TEN)
                    .multiply(BigDecimal.TEN)
                    .divide(BigDecimal.valueOf(curTotal), 2, RoundingMode.HALF_UP);
            trendResult.get(i).setDayRetentionRate(dayRetentionRate);
        }
        // 排序
        if (ReportConstant.QUARTER_TYPE.equals(req.getTimeType())) {
            trendResult = trendResult.stream().sorted(Comparator.comparing(TrendDTO::getQuarterNum))
                    .collect(Collectors.toList());
        } else if (ReportConstant.WEEK_TYPE.equals(req.getTimeType())) {
            trendResult = trendResult.stream().sorted(Comparator.comparing(TrendDTO::getWeekNum))
                    .collect(Collectors.toList());
        } else {
            trendResult = trendResult.stream().sorted(Comparator.comparing(TrendDTO::getGenDate))
                    .collect(Collectors.toList());
        }
        return trendResult;
    }

    /**
     * 日活-趋势
     *
     * @param req
     * @return
     */
    public List<TrendDTO> activityDailyTrend(TrendReq req) {
        // 数据 查询
        Long total = sysUserDailyService.countDailyByDate(req);
        if (Objects.isNull(total)) {
            return Lists.newArrayList();
        }
        List<TrendDTO> trendResult = sysUserDailyService.getDailyByDate(req);
        return processTrendData(req, trendResult, total);
    }

    /**
     * 新增用户-趋势
     *
     * @param req
     * @return
     */
    public List<TrendDTO> registerDailyTrend(TrendReq req) {
        Long total = registerDailyService.countDailyByDate(req);
        if (Objects.isNull(total)) {
            return Lists.newArrayList();
        }
        List<TrendDTO> trendResult = registerDailyService.getDailyByDate(req);
        return processTrendData(req, trendResult, total);
    }

    private List<TrendDTO> processTrendData(TrendReq req, List<TrendDTO> trendResult, Long total) {
        int size = trendResult.size();
        for (int i = 0; i < size; i++) {
            if (i == 0) {
                trendResult.get(i).setAccumulateTotal(total);
                continue;
            }
            TrendDTO before = trendResult.get(i - 1);
            TrendDTO current = trendResult.get(i);
            // 数据当前统计日期的累加新增数量
            Long curNoLoginTotal = Objects.isNull(before.getCurNoLoginTotal()) ? 0L : before.getCurNoLoginTotal();
            current.setAccumulateTotal(before.getAccumulateTotal() - before.getSubTotal() - curNoLoginTotal);
        }
        // 排序
        if (ReportConstant.QUARTER_TYPE.equals(req.getTimeType())) {
            trendResult = trendResult.stream().sorted(Comparator.comparing(TrendDTO::getQuarterNum))
                    .collect(Collectors.toList());
        } else if (ReportConstant.WEEK_TYPE.equals(req.getTimeType())) {
            trendResult = trendResult.stream().sorted(Comparator.comparing(TrendDTO::getWeekNum))
                    .collect(Collectors.toList());
        } else {
            trendResult = trendResult.stream().sorted(Comparator.comparing(TrendDTO::getGenDate))
                    .collect(Collectors.toList());
        }

        for (int i = 0; i < size; i++) {
            if (i == 0) {
                continue;
            }
            TrendDTO before = trendResult.get(i - 1);
            TrendDTO current = trendResult.get(i);
            // 数据当前统计日期的累加新增数量
            Long curNoLoginTotal = Objects.isNull(before.getCurNoLoginTotal()) ? 0L : before.getCurNoLoginTotal();
            current.setBeforeSubTotal(before.getSubTotal() + curNoLoginTotal);
        }
        return trendResult;
    }

    /**
     * 日活-初始化
     *
     * @return
     */
    public Boolean dailyInit() {
        Collection<String> keys = redisService.keys(CacheConstants.DAY_DETAIL_ACTIVITY_ITEM_KEY + "*");
        List<SysUserDaily> insertDataList = Lists.newArrayList();
        for (String catchKey : keys) {
            log.info("catchKey:{}", catchKey);
            SysUserDaily userDaily = new SysUserDaily();
            insertDataList.add(userDaily);
            String[] catchKeys = catchKey.split(":");
            try {
                userDaily.setGenDate(DateUtils.parseDate(catchKeys[3], "yyyyMMdd"));
            } catch (Exception e) {
                log.error("parseDate error:{}", e);
            }
            userDaily.setBrand(catchKeys[4]);
            Long subTotal = redisService.bitCount(catchKey);
            userDaily.setSubTotal(subTotal);
        }
        com.google.common.collect.Lists.partition(insertDataList, 1000).forEach(list -> sysUserDailyService.batchInsert(list));
        return true;
    }

    /**
     * 注册用户-手动导出
     *
     * @param req
     * @return
     */
    public List<UserRegisterDTO> queryRegisterDailyByTime(ManualExportReq req) {
        log.info("queryRegisterDailyByTime:{}", JSONObject.toJSONString(req));
        List<UserRegisterDTO> userRegisterDTOS = registerDailyService.queryRegisterDailyByTime(req);
        /**
         * 补充用户积分数据
         *
         */
        buildPoints(userRegisterDTOS);
        return userRegisterDTOS;
    }

    /**
     * 构建积分数据
     *
     * @param list
     */
    private void buildPoints(List<UserRegisterDTO> list) {
        if (CollUtil.isNotEmpty(list)) {
            Map<Long, PointsBalance> pointsBalanceMap = pointBalanceService.selectMapByUserIds(list.stream()
                    .filter(e -> Objects.nonNull(e.getUserId()) && e.getUserId().compareTo(0L) > 0)
                    .map(UserRegisterDTO::getUserId).collect(Collectors.toList()));
            for (UserRegisterDTO userListDTO : list) {
                PointsBalance pointsBalance = MapUtils.getObject(pointsBalanceMap, userListDTO.getUserId());
                if (Objects.isNull(pointsBalance)) {
                    continue;
                }
                userListDTO.setBalance(pointsBalance.getBalance());
            }
        }
    }

    /**
     * 日活-手动导出
     *
     * @param req
     * @return
     */
    public List<UserDailyDTO> queryDailyByTime(ManualExportReq req) {
        return sysUserDailyService.queryDailyByTime(req);
    }

}
